#region Copyright Notices
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
// 
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#endregion

using System;
using System.Globalization;

namespace Yarr
{
	/// <summary>
	/// A Macro is transforms its arguments into a new expression
	/// which can be passed to the reader. In this way it is
	/// possible to write programs that write programs.
	/// </summary>
	public class Macro
	{
		// The body is a list of Yarr expressions
		private Cons body;

        /// <summary>
        /// Get the body of the macro
        /// </summary>
        public Cons Body { get { return body; } }

		// The list of named arguments
		private Cons argumentNames;

        /// <summary>
        /// Get the argument list for the macro
        /// </summary>
        public Cons Args { get { return argumentNames; } }

		private Environment environment;

        /// <summary>
        /// Construct a Macro
        /// </summary>
        /// <param name="argumentNames">The argument list for the macro</param>
        /// <param name="body">The body for the macro</param>
        /// <param name="environment">The local environment</param>
		public Macro(Cons argumentNames, Cons body, Environment environment)
		{			
			this.body = body;
			this.argumentNames = argumentNames;
			this.environment = environment;
		}

        /// <summary>
        /// Expand the macro
        /// </summary>
        /// <param name="arguments">the macro arguments</param>
        /// <returns>the macro expansion</returns>
		public Object Expand(Cons arguments) 
		{
			// Create a new lexical environment
			Environment localEnvironment = Environment.MakeEnvironment(environment);

			Primitives.ProcessMacroArguments(argumentNames, arguments, localEnvironment);

			object result = null;
			foreach (object o in body) 
				result = Runtime.Eval(o,localEnvironment);

            return result;
		}

		/// <summary>
		/// Returns a string that describes this macro
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return String.Format(CultureInfo.InvariantCulture, "Yarr.Macro (macro {0} {1})", 
				Printer.WriteToString(argumentNames), 
				Printer.WriteToString(body, false));
		}
	}
}
